﻿#region << 文件说明 >>

/*----------------------------------------------------------------
 * 命名空间：Vampirewal.Core.Extensions
 * 唯一标识：5d2f245f-1c0c-48c8-9fef-fb38ffdec83c
 * 文件名：VampirewalCoreExtension
 *
 * 创建者：杨程
 * 电子邮箱：235160615@qq.com
 * 创建时间：2023/10/31 10:22:47
 * 版本：V1.0.0
 * 描述：
 *
 * ----------------------------------------------------------------
 * 修改人：
 * 时间：
 * 修改说明：
 *
 * 版本：V1.0.1
 *----------------------------------------------------------------*/

#endregion << 文件说明 >>

using Microsoft.Extensions.DependencyInjection;
using Vampirewal.Core.Components;

namespace Vampirewal.Core.Extensions;

/// <summary>
/// 扩展方法集中类
/// </summary>
public static class VampirewalCoreExtension
{
    #region AppConfig扩展

    /// <summary>
    /// 将VampirewalCoreConfig添加到IOC容器(务必添加到最前面)
    /// <para>已内置基础配置项,请添加自定义的内容即可</para>
    /// <para>使用options.RegisterOptions</para>
    /// </summary>
    /// <param name="Service"></param>
    /// <param name="ConfigPath">配置文件路径</param>
    /// <param name="Options">配置项</param>
    [Obsolete("20250620 废弃，AddVampirewalCoreAppConfig,后续各配置可以通过IConfigContainer<>在构造函数中注入", true)]
    public static void AddVampirewalCoreConfig(this IServiceCollection Service, string ConfigPath, Action<List<IOptions>> Options)
    {
        VampirewalCoreConfig config = new VampirewalCoreConfig(ConfigPath);

        #region 添加内置配置项

        config.OptionsList.Add(new AppBaseOptions());

        #region 这里交给调用Core的人去添加吧 20231222
        //config.OptionsList.Add(new DbBaseOptions());
        //config.OptionsList.Add(new PagingOptions()); 
        #endregion

        #endregion

        Options?.Invoke(config.OptionsList);

        config.LoadConfig();

        Service.AddSingleton<VampirewalCoreConfig>(config);

        //测试用一下
        //
    }



    /// <summary>
    /// 将配置项注册进VampirewalCoreConfig中
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="Source"></param>
    /// <exception cref="Exception"></exception>
    [Obsolete("20250620 废弃，AddVampirewalCoreAppConfig中的config", true)]
    public static void RegisterOptions<T>(this List<IOptions> Source) where T : class, IOptions
    {
        T t = (T)Activator.CreateInstance(typeof(T));

        if (!Source.Any(a => a.GetType() == t.GetType()))
            Source.Add(t);
        else
            throw new Exception("集合中已经注册了该类型的配置项！");
    }

    /// <summary>
    /// 将VampirewalCoreAppConfig添加到IOC容器(务必添加到最前面)
    /// <para>已内置基础配置项,请添加自定义的内容即可</para>
    /// <para>使用config.LoadOption</para>
    /// </summary>
    /// <param name="services"></param>
    /// <param name="config"></param>
    /// <exception cref="ArgumentNullException"></exception>
    /// <exception cref="Exception"></exception>
    /// <exception cref="InvalidOperationException"></exception>
    public static void AddVampirewalCoreAppConfig(this IServiceCollection services, Action<IVampirewalCoreAppConfig> config)
    {
        if (config == null) throw new ArgumentNullException(nameof(config));

        VampirewalCoreAppConfig appConfig = new VampirewalCoreAppConfig();
        var appOptions = appConfig.LoadOption<AppBaseOptions>();
        config.Invoke(appConfig);
        #region 读取模块

        foreach (var f in appOptions.ModulesPath)
        {
            try
            {
                string filePath = string.Empty;

                if (Path.IsPathRooted(f))
                {
                    filePath = Path.GetFullPath(f);
                }
                else
                {
                    filePath = Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, f));
                }

                Assembly ass = Assembly.LoadFile(filePath);
            }
            catch
            {
                throw new Exception($"无法加载该DLL：{f}");
            }
        }

        var types = AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes()).Where(t => t.GetInterfaces().Contains(typeof(IVampirewalModuleBootStartup))).ToArray();

        Dictionary<string, IVampirewalModuleBootStartup> moduleDic = new Dictionary<string, IVampirewalModuleBootStartup>();

        foreach (var v in types)
        {
            var obj = Activator.CreateInstance(v) as IVampirewalModuleBootStartup;

            obj.LoadModuleOption(appConfig);

            if (!moduleDic.TryAdd(v.Name, obj))
            {
                throw new Exception($"模块名称：{v.Name},重复！");
            }
        }

        VampirewalCoreContext.GetInstance().AddContext("ModuleDic", moduleDic);
        #endregion


        // 获取 GetRequiredService<T> 的泛型方法定义
        //var getRequiredServiceMethod = typeof(ServiceProviderServiceExtensions)
        //    .GetMethod("GetRequiredService", new[] { typeof(IServiceProvider) })
        //    .MakeGenericMethod(typeof(IVampirewalCoreAppConfig));

        //var configContainerBaseType = typeof(ConfigContainer<>);
        //var iConfigContainerBaseType = typeof(IConfigContainer<>);
        //var addSingletonMethodCache = new ConcurrentDictionary<Type, MethodInfo>();

        foreach (var item in appConfig.Options)
        {
            var itemType = item.GetType();

            try
            {
                // 构造泛型类型
                var configContainerType = typeof(ConfigContainer<>).MakeGenericType(itemType);
                var serviceInterfaceType = typeof(IConfigContainer<>).MakeGenericType(itemType);

                // 获取 GetRequiredService<IVampirewalCoreAppConfig>(provider)
                var getRequiredServiceMethod = typeof(ServiceProviderServiceExtensions)
                    .GetMethod("GetRequiredService", new[] { typeof(IServiceProvider) })
                    .MakeGenericMethod(typeof(IVampirewalCoreAppConfig));

                // 构建表达式树
                var serviceProviderParam = Expression.Parameter(typeof(IServiceProvider), "provider");
                var getServiceCall = Expression.Call(
                    null,
                    getRequiredServiceMethod,
                    serviceProviderParam
                );
                var castToConfigManager = Expression.Convert(getServiceCall, typeof(VampirewalCoreAppConfig));
                var newContainer = Expression.New(
                    configContainerType.GetConstructor(new[] { typeof(VampirewalCoreAppConfig) }),
                    castToConfigManager
                );

                // 使用 Func<IServiceProvider, IConfigContainer<T>> 作为委托类型
                var factoryType = typeof(Func<,>).MakeGenericType(typeof(IServiceProvider), serviceInterfaceType);
                var lambda = Expression.Lambda(factoryType, newContainer, serviceProviderParam);
                var factoryDelegate = lambda.Compile();

                // 获取并调用 AddSingleton<IConfigContainer<T>>(services, factory)
                var addSingletonMethod = typeof(ServiceCollectionServiceExtensions)
                    .GetMethods()
                    .First(m => m.IsGenericMethod && m.Name == "AddSingleton" && m.GetParameters().Length == 2)
                    .MakeGenericMethod(serviceInterfaceType);

                addSingletonMethod.Invoke(null, new object[] { services, factoryDelegate });
            }
            catch (Exception ex)
            {
                throw new InvalidOperationException($"注册配置失败：{itemType.Name}", ex);
            }
        }

        VampirewalCoreContext.Instance.AppConfig = appConfig;

        services.AddSingleton<IVampirewalCoreAppConfig>(appConfig);
    }

    ///// <summary>
    ///// 注册配置到IOC容器（自动热更新）
    ///// </summary>
    //public static void RegisterConfig<T>(this IServiceCollection services) where T : class, IOptions, new()
    //{
    //    services.AddSingleton<IConfigContainer<T>>(provider => new ConfigContainer<T>(provider.GetRequiredService<IVampirewalCoreAppConfig>() as VampirewalCoreAppConfig));
    //}

    #endregion

    #region VampirewalCoreDataContext扩展

    /// <summary>
    /// 使用SqlSugar作为数据源
    /// </summary>
    /// <param name="services"></param>
    /// <param name="SqlSugarSetup"></param>
    public static void UseVampirewalCoreSqlSugar(this IServiceCollection services, IVampirewalCoreSqlSugar SqlSugarSetup)
    {
        var DbOptions = VampirewalCoreContext.GetInstance().GetOptions<DbBaseOptions>();

        var dbConnectConfigList = new List<ConnectionConfig>();

        foreach (var item in DbOptions.ConnectionStrings ?? new List<ConnectionString>())
        {
            string connStr = item.Value;

            if (item.DbType == DBTypeEnum.Sqlite)
            {
                var strs = connStr.Split('=');

                if (Path.IsPathRooted(strs[1]))
                {
                    connStr = $"{strs[0]}={strs[1]}";
                }
                else
                {
                    connStr = $"{strs[0]}={AppDomain.CurrentDomain.BaseDirectory}{strs[1]}";
                }

            }

            dbConnectConfigList.Add(SqlSugarSetup.GetDbConnectionConfig(item.Key, connStr, item.DbType));
        }

        SqlSugarScope client = new SqlSugarScope(dbConnectConfigList, db =>
        {
            foreach (var item in DbOptions.ConnectionStrings)
            {
                //SQL执行完
                db.GetConnection(item.Key).Aop.OnLogExecuted = SqlSugarSetup.OnLogExecuted;
                //SQL执行前
                db.GetConnection(item.Key).Aop.OnLogExecuting = SqlSugarSetup.OnLogExecuting;

                //SQL报错
                db.GetConnection(item.Key).Aop.OnError = SqlSugarSetup.OnError;

                //可以修改SQL和参数的值
                db.GetConnection(item.Key).Aop.OnExecutingChangeSql = SqlSugarSetup.OnExecutingChangeSql;

                db.GetConnection(item.Key).Aop.DataExecuting = SqlSugarSetup.DataExecuting;
                db.GetConnection(item.Key).Aop.DataExecuted = SqlSugarSetup.DataExecuted;
            }
        });
        SqlSugarSetup.SetClient(client);

        client.DbMaintenance.CreateDatabase();

        #region 20250304 为了方便加载module中的实体，这里改成使用反射来加载

        var types = AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes()).Where(u => !u.IsInterface && !u.IsAbstract && u.IsClass && u.IsDefined(typeof(SugarTable), false)).ToArray();

        types = SqlSugarSetup.FilterSugarTableType(types);

        foreach (var item in types)
        {
            if (item.GetCustomAttribute<SplitTableAttribute>() == null)
                client.CodeFirst.InitTables(item);
            else
                client.CodeFirst.SplitTables().InitTables(item);
        }

        #endregion


        //SqlSugarSetup.CodeFirst();
        SqlSugarSetup.InitData();

        services.AddSingleton<ISqlSugarClient>(client);
    }

    /// <summary>
    /// 使用SqlSugar作为数据源
    /// </summary>
    /// <typeparam name="SqlSugarSetup"></typeparam>
    /// <param name="services"></param>
    public static void UseVampirewalCoreSqlSugar<SqlSugarSetup>(this IServiceCollection services) where SqlSugarSetup : IVampirewalCoreSqlSugar
    {
        Type SetupType = typeof(SqlSugarSetup);

        var Setup = (IVampirewalCoreSqlSugar)Activator.CreateInstance(SetupType);

        var DbOptions = VampirewalCoreContext.GetInstance().GetOptions<DbBaseOptions>();

        var dbConnectConfigList = new List<ConnectionConfig>();

        foreach (var item in DbOptions.ConnectionStrings ?? new List<ConnectionString>())
        {
            string connStr = item.Value;

            if (item.DbType == DBTypeEnum.Sqlite)
            {
                var strs = connStr.Split('=');

                if (Path.IsPathRooted(strs[1]))
                {
                    connStr = $"{strs[0]}={strs[1]}";
                }
                else
                {
                    connStr = $"{strs[0]}={AppDomain.CurrentDomain.BaseDirectory}{strs[1]}";
                }
            }

            dbConnectConfigList.Add(Setup.GetDbConnectionConfig(item.Key, connStr, item.DbType));
        }

        SqlSugarScope client = new SqlSugarScope(dbConnectConfigList, db =>
        {
            foreach (var item in DbOptions.ConnectionStrings)
            {
                //SQL执行完
                db.GetConnection(item.Key).Aop.OnLogExecuted = Setup.OnLogExecuted;
                //SQL执行前
                db.GetConnection(item.Key).Aop.OnLogExecuting = Setup.OnLogExecuting;

                //SQL报错
                db.GetConnection(item.Key).Aop.OnError = Setup.OnError;

                //可以修改SQL和参数的值
                db.GetConnection(item.Key).Aop.OnExecutingChangeSql = Setup.OnExecutingChangeSql;

                db.GetConnection(item.Key).Aop.DataExecuting = Setup.DataExecuting;
                db.GetConnection(item.Key).Aop.DataExecuted = Setup.DataExecuted;
            }
        });
        Setup.SetClient(client);

        client.DbMaintenance.CreateDatabase();

        #region 20250304 为了方便加载module中的实体，这里改成使用反射来加载

        var types = AppDomain.CurrentDomain.GetAssemblies().SelectMany(a => a.GetTypes()).Where(u => !u.IsInterface && !u.IsAbstract && u.IsClass && u.IsDefined(typeof(SugarTable), false)).ToArray();

        types = Setup.FilterSugarTableType(types);

        foreach (var item in types)
        {
            if (item.GetCustomAttribute<SplitTableAttribute>() == null)
                client.CodeFirst.InitTables(item);
            else
                client.CodeFirst.SplitTables().InitTables(item);
        }

        #endregion

        //Setup.CodeFirst();
        Setup.InitData();

        services.AddSingleton<ISqlSugarClient>(client);
    }

    #endregion

    #region DialogMessage扩展

    /// <summary>
    /// 将IVampirewalCoreDialogMessage注册进容器
    /// </summary>
    /// <param name="services"></param>
    public static void AddVampirewalCoreDialogMessage(this IServiceCollection services)
    {
        services.AddSingleton<IVampirewalCoreDialogMessage, VampirewalCoreDialogService>();
    }

    /// <summary>
    /// 打开自定义实体选择窗口
    /// </summary>
    /// <typeparam name="T"></typeparam>
    /// <param name="dialog"></param>
    /// <param name="FuncSetting">无需设置UcView</param>
    /// <param name="result"></param>
    /// <exception cref="Exception"></exception>
    public static void OpenCustomSelectorView<T>(this IVampirewalCoreDialogMessage dialog, Func<DialogWindowSetting> FuncSetting, Action<List<T>> result) where T : TopModel
    {
        if (FuncSetting == null)
            throw new ArgumentNullException("弹窗设置不能为null！");

        var setting = FuncSetting.Invoke();

        if (setting.PassData == null || setting.PassData is IList data && data.Count == 0)
            throw new Exception("传递过来的数据源不能为空或null！");

        if (result == null)
            throw new Exception("获取结果的委托不能为空");

        setting.UcView = WindowsManager.Instance.GetView("CustomSelectorView");

        var selectData = dialog.OpenDialogWindow(setting);

        if (selectData != null && selectData is IList list)
        {
            List<T> current = new List<T>();

            foreach (var item in list)
            {
                var value = item as T;
                current.Add(value);
            }

            result.Invoke(current);
        }
    }

    #endregion

    /// <summary>
    /// 将IVampirewalCoreMdiViewService注册进容器
    /// </summary>
    /// <param name="services"></param>
    public static void AddVampirewalCoreMdiService(this IServiceCollection services)
    {
        services.AddSingleton<IVampirewalCoreMdiViewService, VampirewalCoreMdiViewService>();
    }

    /// <summary>
    /// 使用IVampirewalCoreEventAggregatorService事件聚合器
    /// </summary>
    /// <param name="services"></param>
    public static void AddVampirewalCoreEventAggregatorService(this IServiceCollection services)
    {
        services.AddSingleton<IVampirewalCoreEventAggregatorService, VampirewalCoreEventAggregatorService>();
    }
}

